import os
import pymysql
import re
import sys

from PyQt5 import QtWidgets
from PyQt5.QtWidgets import QMainWindow, QFileDialog, QApplication, QMessageBox as qm, QInputDialog, QLineEdit

from mainwindow import Ui_MainWindow


class MyMainForm(QMainWindow, Ui_MainWindow):
    def __init__(self, parent=None):
        # 类变量默认值
        self.host = "124.70.68.52"
        self.user = ""
        self.password = ""
        self.author = 'xiny'
        self.basePath = 'D:/main/java/cn/qdhlm/hems'
        self.javapath = 'cn.qdhlm.hems'
        self.goalpath = 'D:/MyProject/generate/src'
        self.port = '3336'
        self.data_base = 'hems'
        # 连接数据库
        self.db = "information_schema"
        self.conn = None
        self.cursor = None
        self.tables = ''
        # 查表名
        self.sql1 = """SELECT TABLE_NAME FROM `TABLES` WHERE TABLE_SCHEMA = %s"""
        # 查字段和字段类型
        self.sql = """SELECT COLUMN_NAME,DATA_TYPE FROM `COLUMNS` WHERE TABLE_NAME = %s AND TABLE_SCHEMA = %s"""
        # 界面窗口初始化
        super(MyMainForm, self).__init__(parent)
        self.setupUi(self)
        self.openFileButton.clicked.connect(self.openFile)
        self.pushButton.clicked.connect(self.generate_init)
        self.pushButton_2.clicked.connect(self.go_generate)
        self.pushButton_2.setStyleSheet(
            '''QPushButton{background:#6DDF6D;border-radius:5px;}QPushButton:hover{background:green;}''')
        self.pushButton.setStyleSheet(
            '''QPushButton{background:#6DDF6D;border-radius:5px;}QPushButton:hover{background:green;}''')
        self.openFileButton.setStyleSheet(
            '''QPushButton{background:#6DDF6D;border-radius:5px;}QPushButton:hover{background:green;}''')
        self.entry_host.setText(self.host)
        self.entry_port.setText(self.port)
        self.entry_user.setText(self.user)
        self.entry_pwd.setText(self.password)
        # 隐藏密码
        self.entry_pwd.setEchoMode(QtWidgets.QLineEdit.Password)
        self.entry_db.setText(self.data_base)
        self.entry_company.setText(self.javapath)
        self.entry_author.setText(self.author)
        self.filePathlineEdit.setText(self.goalpath)
        # 进度
        self.progressBar.setValue(0)

    # 写basemapper
    def write_baseMapper(self):
        file = open(self.basePath + '/mapper/master/BaseMapper.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.mapper.master;

import org.apache.ibatis.annotations.Param;

import java.util.List;
import java.util.Map;

/**
 * @Name: BaseMapper
 * @Description: BaseMapper
 * @author: ''' + self.author + '''
**/
public interface BaseMapper<DO, VO, QUERY> {
    /**
     * 根据Id 获取记录
     *
     * @param id
     * @return
     */
    VO get(Integer id);

     /**
     * 查询列表
     *
     * @param t
     * @return
     */
    List<VO> findList(QUERY t);

     /**
      * 添加记录
      *
      * @param t
      * @return
     */
    Integer insert(DO t);

     /**
      * 修改记录
      *
      * @param t
      * @return
         */
    Integer update(DO t);

    /**
     * 根据记录 idStr 删除记录
     *
     * @param idStr
     * @return
     */
    Integer delete(@Param("idStr") String idStr);
    }
     ''')
        file.flush()
        file.close()

    # 写constant
    def write_constant(self):
        file = open(self.basePath + '/common/Constant.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.common;

/**
 * @Name: Constant
 * @Description: Constant
 * @Author: ''' + self.author + '''
 */
public class Constant {
    /**
     * 默认 授权验证：测试环境使用
     */
    public static final String AUTHORIZATION_DEFAULT = "qdhlm";

    /**
     * 微服务名前缀
     */
    public static final String SERVICE_NAME_PREFIX = "hems-";

    /**
     * 默认分页参数
     */
    public static final int PAGE_NUM = 1;
    public static final int PAGE_SIZE = 20;

    /**
     * 树层级
     */
    public static final String TREE_LEVEL_CUSTOMER = "customer";
    public static final String TREE_LEVEL_COMMUNITY = "community";
    public static final String TREE_LEVEL_BUILDING = "building";
    public static final String TREE_LEVEL_UNIT = "unit";
    public static final String TREE_LEVEL_HOUSEHOLD = "household";
    public static final String TREE_LEVEL_COLLECTOR = "collector";
    public static final String TREE_LEVEL_METER = "meter";
    public static final String TREE_LEVEL_HEAT_EXCHANGE_STATION = "heatExchangeStation";
    public static final String TREE_LEVEL_RING_ROAD = "ringRoad";

    /**
     * 所属客户 树 PURPOSE
     */
    public static final String CUSTOMER_TREE_PURPOSE_CUSTOMER = "customer";
    public static final String CUSTOMER_TREE_PURPOSE_COMMUNITY = "community";
    public static final String CUSTOMER_TREE_PURPOSE_CHARGE_FACTOR = "chargeFactor";
    public static final String CUSTOMER_TREE_PURPOSE_HEAT_EXCHANGE_STATION = "heatExchangeStation";
    public static final String CUSTOMER_TREE_PURPOSE_DEVICE_JOIN = "deviceJoin";
    public static final String CUSTOMER_TREE_PURPOSE_TESTING_ITEM = "testingItem";

    /**
     * 角色下拉列表 PURPOSE
     */
    public static final String ROLE_SELECT_PURPOSE_USER = "user";
    public static final String ROLE_SELECT_PURPOSE_ROLE = "role";

    /**
     * 日期格式
     */
    public static final String DATE_FORMAT_SECOND = "yyyy-MM-dd HH:mm:ss";
    public static final String DATE_FORMAT_DAY = "yyyy-MM-dd";
    public static final String DATE_FORMAT_MONTH = "yyyy-MM";
    public static final String DATE_FORMAT_MONTH_DAY = "MM-dd";
    public static final String DATE_FORMAT_YEAR = "yyyy";

    /**
     * 用量统计方式
     */
    public static final int DOSAGE_WAY_DAY = 1;
    public static final int DOSAGE_WAY_MONTH = 2;
    public static final int DOSAGE_WAY_SEASON = 3;

    public static final int LENGTH_COLLECTOR_NO = 10;
    public static final int LENGTH_TERMINAL_MAC_ADDR = 14;
    public static final int LENGTH_TERMINAL_MAC_ADDR_MODBUS = 2;

    public static final String PROTOCOL_PREFIX_MODBUS = "modbus";

    /**
     * 采集器允许下挂终端最大数
     */
    public static final int COLLECTOR_MOUNT_TERMINAL_MAX_COUNT = 256;

    /**
     * 采暖季间隔日期
     */
    public static final String HEATING_SEASON_DATE = "09-30";

    /**
     * 导出类型：0-全部；1-起止
     */
    public static final int EXPORT_TYPE_ALL = 0;
    public static final int EXPORT_TYPE_START_END = 1;

    /**
     * 导出检测记录：-1-全部
     */
    public static final int EXPORT_TYPE_TESTING_ALL = -1;

    /**
     * 导出数量最大值
     */
    public static final int EXPORT_MAX_NUM = 10000;

    /**
     * 抄表数据日期跨度：1-当天；2-最近一周；3-最近一月；4-当前采暖季；5-自定义
     */
    public static final int DATA_DATE_SPAN_DAY = 1;
    public static final int DATA_DATE_SPAN_WEEK = 2;
    public static final int DATA_DATE_SPAN_MONTH = 3;
    public static final int DATA_DATE_SPAN_SEASON = 4;
    public static final int DATA_DATE_SPAN_CUSTOM = 5;

    /**
     * 终端类型：2-热表；5-阀门；6-表阀一体；7-测量点
     */
    public static final int TERMINAL_TYPE_METER = 2;
    public static final int TERMINAL_TYPE_VALVE = 5;
    public static final int TERMINAL_TYPE_METER_VALVE = 6;
    public static final int TERMINAL_TYPE_MEASURE_POINT = 7;

    /**
     * 终端层级：1-户；2-总
     */
    public static final int TERMINAL_LEVEL_HOUSEHOLD = 1;
    public static final int TERMINAL_LEVEL_SUMMARY = 2;

    /**
     * 终端接入模式
     * 1-IOT_MQTT；2-NB_IOT_MQTT；
     * 3-NB_IOT_TELECOM；4-NB_IOT_ONENET；
     * 5-IOT_HUAWEI
     * 6-IOT_SOCKET
     */
    public static final int TERMINAL_JOIN_MODE_IOT_MQTT = 1;
    public static final int TERMINAL_JOIN_MODE_NB_IOT_MQTT = 2;
    public static final int TERMINAL_JOIN_MODE_NB_IOT_TELECOM = 3;
    public static final int TERMINAL_JOIN_MODE_NB_IOT_ONENET = 4;
    public static final int TERMINAL_JOIN_MODE_IOT_HUAWEI = 5;
    public static final int TERMINAL_JOIN_MODE_IOT_SOCKET = 6;

    /**
     * 终端型号：
     * 0-MDC500终端；
     * <p>
     * 1-WAC300_NB移动调节阀；2-WAC400_NB移动锁闭阀；3-NBC100_NB移动模块；4-NBT200_NB移动测温插座；10-NTR200_NB移动温湿度测量点；
     * 12-WAC500_NB移动调节阀；14-NBT200_AC_NB移动测量点；16-WAC320_NB移动调节阀；
     * <p>
     * 5-NBC100_NB电信模块；6-WAC300_NB电信调节阀；7-WAC400_NB电信锁闭阀；9-NTR200_NB电信温湿度测量点；11-WAC500_NB电信调节阀；
     * 13-NBT200_AC_NB电信测量点；15-WAC320_NB电信调节阀；17-NBT200_NB电信测温插座；19-WAC350_NB电信锁闭阀；20-WAC200_JY_HH_NB电信调节阀；
     * 21-WAC510_NB电信调节阀；22-WAC330_NB电信调节阀；
     * <p>
     * 8-MDC500OC终端；
     * <p>
     * 18-MTU500AC终端；s
     */
    public static final int TERMINAL_MODEL_MDC500 = 0;
    public static final int TERMINAL_MODEL_ADJUST_VALVE_WAC300 = 1;
    public static final int TERMINAL_MODEL_LOCK_VALVE_WAC400 = 2;
    public static final int TERMINAL_MODEL_MODULE_NBC100 = 3;
    public static final int TERMINAL_MODEL_MEASURE_SOCKET = 4;
    public static final int TERMINAL_MODEL_TELECOM_MODULE_NBC100 = 5;
    public static final int TERMINAL_MODEL_TELECOM_ADJUST_VALVE_WAC300 = 6;
    public static final int TERMINAL_MODEL_TELECOM_LOCK_VALVE_WAC400 = 7;
    public static final int TERMINAL_MODEL_MDC500OC = 8;
    public static final int TERMINAL_MODEL_TELECOM_MEASURE_POINT_NTR200 = 9;
    public static final int TERMINAL_MODEL_MEASURE_POINT_NTR200 = 10;
    public static final int TERMINAL_MODEL_TELECOM_ADJUST_VALVE_WAC500 = 11;
    public static final int TERMINAL_MODEL_ADJUST_VALVE_WAC500 = 12;
    public static final int TERMINAL_MODEL_TELECOM_MEASURE_POINT_NBT200_AC = 13;
    public static final int TERMINAL_MODEL_MEASURE_POINT_NBT200_AC = 14;
    public static final int TERMINAL_MODEL_TELECOM_ADJUST_VALVE_WAC320 = 15;
    public static final int TERMINAL_MODEL_ADJUST_VALVE_WAC320 = 16;
    public static final int TERMINAL_MODEL_TELECOM_MEASURE_SOCKET = 17;
    public static final int TERMINAL_MODEL_MTU500AC = 18;
    public static final int TERMINAL_MODEL_TELECOM_LOCK_VALVE_WAC350 = 19;
    public static final int TERMINAL_MODEL_TELECOM_ADJUST_VALVE_WAC200_JY_HH = 20;
    public static final int TERMINAL_MODEL_TELECOM_ADJUST_VALVE_WAC520 = 21;
    public static final int TERMINAL_MODEL_TELECOM_ADJUST_VALVE_WAC330 = 22;
    public static final int TERMINAL_MODEL_TELECOM_LOCK_VALVE_WAC550 = 23;

    /**
     * 采集器类型：1-智能采集器；2-透传采集器
     */
    public static final int COLLECTOR_TYPE_INTELLIGENT = 1;
    public static final int COLLECTOR_TYPE_TRANSPARENT = 2;

    /**
     * 采集器型号：0-MDC500, 1-MDC500OC，2-MTU500AC
     */
    public static final int COLLECTOR_MODEL_MDC500 = 0;
    public static final int COLLECTOR_MODEL_MDC500OC = 1;
    public static final int COLLECTOR_MODEL_MTU500AC = 2;

    /**
     * 计费系数类型：1-默认；2-自定义
     */
    public static final int CHARGE_FACTOR_TYPE_DEFAULT = 1;
    public static final int CHARGE_FACTOR_TYPE_CUSTOM = 2;

    /**
     * 故障指标类型：1-预设；2-自定义 3-固化
     */
    public static final int FAULT_INDEX_TYPE_PRESET = 1;
    public static final int FAULT_INDEX_TYPE_CUSTOM = 2;
    public static final int FAULT_INDEX_TYPE_SOLIDIFY = 3;

    /**
     * 采集器升级版本FTP服务器
     */
    public static final String FTP_VERSION_HOST = "dtu.qdhlm.cn";
    public static final int FTP_VERSION_PORT = 21;
    public static final String FTP_VERSION_USER = "collector";
    public static final String FTP_VERSION_PASSWORD = "collector";

    /**
     * 物联网平台：1-电信；3-华为
     */
    public static final int IOT_PLATFORM_TELECOM = 1;
    public static final int IOT_PLATFORM_HUAWEI = 3;

    /**
     * 物联网通知类型：命令状态变化
     */
    public static final String IOT_NOTIFY_TYPE_COMMAND_STATUS_CHANGED = "commandStatusChanged";
}

        ''')

    def write_base_query(self):
        file = open(self.basePath + '/model/query/BaseQuery.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.model.query;

import io.swagger.annotations.ApiModelProperty;
import lombok.Data;

import java.util.List;
import java.util.Map;

/**
 * @Name: BaseQuery
 * @Description: BaseQuery
 * @author: ''' + self.author + '''
**/
@Data
public class BaseQuery {
    @ApiModelProperty(hidden = true)
    private Integer loginCustomerId;
    @ApiModelProperty(hidden = true)
    private List<Map<String, Object>> searchList;
    @ApiModelProperty(hidden = true)
    private String orderBy;
}''')
        file.flush()
        file.close()

    def write_page_util(self):
        file = open(self.basePath + '/common/util/PageUtil.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.common.util;

import ''' + self.javapath + '''.common.Constant;
import com.github.pagehelper.PageHelper;

/**
 * @Name: PageUtil
 * @Description: PageUtil
 * @Author: ''' + self.author + '''
 */
public class PageUtil {
    /**
     * 分页操作
     *
     * @param pageNum
     * @param pageSize
     */
    public static void start(Integer pageNum, Integer pageSize) {
        if (null == pageNum) {
            pageNum = Constant.PAGE_NUM;
        }
        if (null == pageSize) {
            pageSize = Constant.PAGE_SIZE;
        }
        PageHelper.startPage(pageNum, pageSize);
    }
}
        ''')

    def write_main(self):
        app_name = self.get_app_name(self.javapath)
        file = open(self.basePath + '/' + app_name + 'Application.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + ''';

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

/**
 * @Name: ''' + app_name + '''Application
 * @Description: ''' + app_name + '''Application
 * @author: ''' + self.author + '''
 **/
@SpringBootApplication
public class ''' + app_name + '''Application {
    /**
     * 启动入口
     *
     * @param args
     */
    public static void main(String[] args) {
        SpringApplication.run(''' + app_name + '''Application.class, args);
    }
}''')
        file.flush()
        file.close()

    def write_entity_util(self):
        file = open(self.basePath + '/common/util/EntityUtil.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.common.util;

import lombok.extern.log4j.Log4j2;

import java.lang.reflect.Field;
import java.lang.reflect.Method;

/**
 * @Name: EntityUtil
 * @Description: EntityUtil
 * @author: ''' + self.author + '''
 */
@Log4j2
public class EntityUtil {
    /**
     * 进行实体类整体赋值
     *
     * @param sourObject
     * @param destObject
     * @throws Exception
     */
    public static void copyEntity2Entity(Object sourObject, Object destObject) throws Exception {
        // 获取实体类的属性Filed数组
        Field[] fields = Class.forName(sourObject.getClass().getCanonicalName()).getDeclaredFields();
        for (Field field : fields) {
            // 获取set参数类型
            Class<?>[] parameterTypes = new Class[1];
            parameterTypes[0] = field.getType();
            // 调用本类中的帮助方法来获取当前属性名对应的方法名（“get”为getMethodName方法的第二个参数）
            String methodGetName = getMethodName(field.getName(), "get");
            String methodSetName = getMethodName(field.getName(), "set");
            try {
                // 根据获取的方法名称及当前field的类型获取method对象
                Method methodGet = sourObject.getClass().getDeclaredMethod(methodGetName);
                Method methodSet = destObject.getClass().getDeclaredMethod(methodSetName, parameterTypes);
                // 调用当前实体类的方法将数值get出来
                Object obj = methodGet.invoke(sourObject);
                // 若为""，也修改
                if (obj != null) {
                    methodSet.invoke(destObject, obj);
                }
            } catch (Exception e) {
                // 目标类中不包含 该方法，则跳过
                log.error("实体赋值异常：{}，{}", methodGetName, methodSetName);
            }
        }
    }

    /**
     * method name
     *
     * @param fieldName
     * @param methodType
     * @return
     */
    private static String getMethodName(String fieldName, String methodType) {
        String methodName = fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
        return methodType + methodName;
    }
}''')
        file.flush()
        file.close()

    def write_rs(self):
        file = open(self.basePath + '/common/rs/Rs.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.common.rs;

import lombok.Data;
import lombok.extern.log4j.Log4j2;
import org.springframework.transaction.NoTransactionException;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

/**
 * @Name: Rs
 * @Description: Rs
 * @author: ''' + self.author + '''
 **/
@Log4j2
@Data
public class Rs {
    private int s;
    private String msg;
    private Object data;

    public static Rs ok() {
        Rs rs = new Rs();
        rs.setS(0);
        return rs;
    }

    public static Rs ok(String msg) {
        Rs rs = ok();
        rs.setMsg(msg);
        return rs;
    }

    public static Rs ok(String msg, Object data) {
        Rs rs = ok(msg);
        // data
        rs.setData(data);
        return rs;
    }

    public static Rs bad() {
        Rs rs = new Rs();
        rs.setS(-1);
        // 事务回滚
        rollback();
        return rs;
    }

    public static Rs bad(String msg) {
        Rs rs = bad();
        rs.setMsg(msg);
        // 事务回滚
        rollback();
        return rs;
    }

    private static void rollback() {
        TransactionStatus currentTransactionStatus = null;
        try {
            currentTransactionStatus = TransactionAspectSupport.currentTransactionStatus();
        } catch (NoTransactionException e) {
        } finally {
            if (currentTransactionStatus != null && !currentTransactionStatus.isRollbackOnly()) {
                currentTransactionStatus.setRollbackOnly();
            }
        }
    }
}
    ''')
        file.flush()
        file.close()
        file = open(self.basePath + '/common/rs/PageRs.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.common.rs;

import com.github.pagehelper.PageInfo;
import lombok.Data;

import java.util.List;

/**
 * @Name: PageRs
 * @Description: PageRs
 * @author: ''' + self.author + '''
 */
@Data
public class PageRs {
    /**
     * 结果
     */
    private int s;
    /**
     * 信息
     */
    private String msg;
    /**
     * 分页
     */
    private int pageNum;
    private int pageSize;
    private int pages;
    private long total;
    private List<?> list;

    public static PageRs ok(PageInfo<?> pageInfo) {
        PageRs pageRs = new PageRs();
        pageRs.setS(0);
        pageRs.setPageNum(pageInfo.getPageNum());
        pageRs.setPageSize(pageInfo.getPageSize());
        pageRs.setPages(pageInfo.getPages());
        pageRs.setTotal(pageInfo.getTotal());
        pageRs.setList(pageInfo.getList());
        return pageRs;
    }

    public static PageRs bad(String msg) {
        PageRs pageRs = new PageRs();
        pageRs.setS(-1);
        pageRs.setMsg(msg);
        return pageRs;
    }
}
    ''')
        file.flush()
        file.close()

    def write_controller(self, name):
        handled_name = self.getClassNameStr(name)
        file = open(self.basePath + '/controller/' + handled_name + 'Controller.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.controller;

import ''' + self.javapath + '''.common.rs.PageRs;
import ''' + self.javapath + '''.common.rs.Rs;
import ''' + self.javapath + '''.model.dto.''' + handled_name + '''DTO;
import ''' + self.javapath + '''.model.query.''' + handled_name + '''Query;
import ''' + self.javapath + '''.service.''' + handled_name + '''Service;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

/**
 * @Name: ''' + handled_name + '''Controller
 * @Description: ''' + handled_name + '''Controller
 * @author: ''' + self.author + '''
 */
@Api(tags = "")
@RequestMapping("")
@RestController
public class ''' + handled_name + '''Controller {
    @Autowired
    private ''' + handled_name + '''Service ''' + self.first_low(handled_name) + '''Service;

    @ApiOperation("分页查询")
    @GetMapping("page")
    public PageRs page(''' + handled_name + '''Query ''' + self.first_low(handled_name) + '''Query, String search, Integer pageNum, Integer pageSize) {
        return ''' + self.first_low(handled_name) + '''Service.page(''' + self.first_low(handled_name) + '''Query, search, pageNum, pageSize);
    }

    @ApiOperation("修改")
    @PutMapping
    public Rs update(''' + handled_name + '''DTO ''' + self.first_low(handled_name) + '''DTO) {
        return ''' + self.first_low(handled_name) + '''Service.update(''' + self.first_low(handled_name) + '''DTO);
    }

    @ApiOperation("新增")
    @PostMapping
    public Rs insert(''' + handled_name + '''DTO ''' + self.first_low(handled_name) + '''DTO) {
        return ''' + self.first_low(handled_name) + '''Service.insert(''' + self.first_low(handled_name) + '''DTO);
    }

    @ApiOperation("删除")
    @DeleteMapping
    public Rs delete(String idStr) {
        return ''' + self.first_low(handled_name) + '''Service.delete(idStr);
    }
}
    ''')
        file.flush()
        file.close()

    def write_service(self, name):
        handled_name = self.getClassNameStr(name)

        file = open(self.basePath + '/service/' + handled_name + 'Service.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.service;

import ''' + self.javapath + '''.common.rs.PageRs;
import ''' + self.javapath + '''.common.rs.Rs;
import ''' + self.javapath + '''.common.util.PageUtil;
import ''' + self.javapath + '''.common.util.EntityUtil;
import ''' + self.javapath + '''.mapper.master.''' + handled_name + '''Mapper;
import ''' + self.javapath + '''.model.dto.''' + handled_name + '''DTO;
import ''' + self.javapath + '''.model.''' + handled_name + '''DO;
import ''' + self.javapath + '''.model.query.''' + handled_name + '''Query;
import com.github.pagehelper.PageInfo;
import lombok.extern.log4j.Log4j2;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * @Name: ''' + handled_name + '''Service
 * @Description: ''' + handled_name + '''Service
 * @author: ''' + self.author + '''
 */
@Log4j2
@Service
public class ''' + handled_name + '''Service {
    @Autowired
    private ''' + handled_name + '''Mapper ''' + self.first_low(handled_name) + '''Mapper;

    public PageRs page(''' + handled_name + '''Query ''' + self.first_low(handled_name) + '''Query, String search, Integer pageNum, Integer pageSize) {
        PageUtil.start(pageNum, pageSize);
        return PageRs.ok(new PageInfo<>(''' + self.first_low(
            handled_name) + '''Mapper.findList(''' + self.first_low(
            handled_name) + '''Query)));
    }

    public Rs insert(''' + handled_name + '''DTO ''' + self.first_low(handled_name) + '''DTO) {
        int count;
        try {
            ''' + handled_name + '''DO ''' + self.first_low(handled_name) + '''DO = new ''' + handled_name + '''DO();
            EntityUtil.copyEntity2Entity(''' + self.first_low(handled_name) + '''DTO, ''' + self.first_low(
            handled_name) + '''DO);
            count = ''' + self.first_low(handled_name) + '''Mapper.insert(''' + self.first_low(handled_name) + '''DO);
            if (count <= 0) {
                return Rs.bad("''' + self.first_low(handled_name) + '''新增失败：数据库执行操作失败");
            }
            return Rs.ok();
        } catch (Exception e) {
            log.error("''' + handled_name + '''新增失败: 数据处理异常", e);
            return Rs.bad("''' + handled_name + '''新增失败: 数据处理异常");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Rs update(''' + handled_name + '''DTO ''' + self.first_low(handled_name) + '''DTO) {
        int count;
        try {
            ''' + handled_name + '''DO ''' + self.first_low(handled_name) + '''DO = new ''' + handled_name + '''DO();
            EntityUtil.copyEntity2Entity(''' + self.first_low(handled_name) + '''DTO, ''' + self.first_low(
            handled_name) + '''DO);
            count = ''' + self.first_low(handled_name) + '''Mapper.update(''' + self.first_low(handled_name) + '''DO);
            if (count <= 0) {
                return Rs.bad("''' + handled_name + '''修改失败：数据库执行操作失败");
            }
            return Rs.ok();
        } catch (Exception e) {
            log.error("''' + handled_name + '''修改失败: 数据处理异常", e);
            return Rs.bad("''' + handled_name + '''修改失败: 数据处理异常");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    public Rs delete(String idStr) {
        int count = ''' + self.first_low(handled_name) + '''Mapper.delete(idStr);
        if (count <= 0) {
            return Rs.bad("''' + handled_name + '''记录删除失败：数据库执行操作失败");
        }
        return Rs.ok();
    }
}
    ''')
        file.flush()
        file.close()

    def write_mapper(self, name):
        handled_name = self.getClassNameStr(name)
        file = open(self.basePath + '/mapper/master/' + handled_name + 'Mapper.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.mapper.master;

import ''' + self.javapath + '''.model.''' + handled_name + '''DO;
import ''' + self.javapath + '''.model.query.''' + handled_name + '''Query;
import ''' + self.javapath + '''.model.vo.''' + handled_name + '''VO;
import org.apache.ibatis.annotations.Mapper;
import org.springframework.stereotype.Repository;

/**
 * @Name: ''' + handled_name + '''Mapper
 * @Description: ''' + handled_name + '''Mapper
 * @author: ''' + self.author + '''
 */
@Mapper
@Repository
public interface ''' + handled_name + '''Mapper extends BaseMapper<''' + handled_name + '''DO, ''' + handled_name + '''VO, ''' + handled_name + '''Query> {
}
    ''')
        file.flush()
        file.close()

    def write_VO(self, name):
        handled_name = self.getClassNameStr(name)
        file = open(self.basePath + '/model/vo/' + handled_name + 'VO.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.model.vo;

import com.fasterxml.jackson.annotation.JsonInclude;
import lombok.Data;

import java.util.Date;

/**
 * @Name: ''' + handled_name + '''VO
 * @Description: ''' + handled_name + '''VO
 * @author: ''' + self.author + '''
 */
@Data
@JsonInclude(JsonInclude.Include.NON_NULL)
public class ''' + handled_name + '''VO {\n''')
        self.write_model(file, name)
        file.write('}\n')
        file.flush()
        file.close()

    def write_DO(self, name):
        handled_name = self.getClassNameStr(name)
        file = open(self.basePath + '/model/' + handled_name + 'DO.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.model;

import lombok.Data;

import java.util.Date;

/**
 * @Name: ''' + handled_name + '''DO
 * @Description: ''' + handled_name + '''DO
 * @author: ''' + self.author + '''
 */
@Data
public class ''' + handled_name + '''DO {\n''')
        self.write_model(file, name)
        file.write('}\n')
        file.flush()
        file.close()

    def write_DTO(self, name):
        handled_name = self.getClassNameStr(name)
        file = open(self.basePath + '/model/dto/' + handled_name + 'DTO.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.model.dto;

import lombok.Data;

import java.util.Date;

/**
 * @Name: ''' + handled_name + '''DTO
 * @Description: ''' + handled_name + '''DTO
 * @author: ''' + self.author + '''
 */
@Data
public class ''' + handled_name + '''DTO {\n''')
        self.write_model(file, name)
        file.write('}\n')
        file.flush()
        file.close()

    def write_Query(self, name):
        handled_name = self.getClassNameStr(name)
        file = open(self.basePath + '/model/query/' + handled_name + 'Query.java', 'w', encoding='utf-8')
        file.writelines('''package ''' + self.javapath + '''.model.query;

import lombok.Data;

import java.util.Date;

/**
 * @Name: ''' + handled_name + '''Query
 * @Description: ''' + handled_name + '''Query
 * @author: ''' + self.author + '''
 */
@Data
public class ''' + handled_name + '''Query extends BaseQuery {\n''')
        self.write_model(file, name)
        file.write('}\n')
        file.flush()
        file.close()

    def write_xml(self, name):
        handled_name = self.getClassNameStr(name)
        file = open(self.goalpath + '/main/resources/mapper/master/' + handled_name + 'Mapper.xml', 'w',
                    encoding='utf-8')
        file.write('<?xml version="1.0" encoding="UTF-8"?>\n')
        file.write('<mapper namespace="' + self.javapath + '.mapper.master.' + handled_name + 'Mapper">\n')
        file.write(
            '<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" >\n')
        file.write('    <resultMap id="baseResultMap" type="' + self.javapath + '.model.vo.' + handled_name + 'VO">\n')
        file.write('        <id column="id" property="id"/>\n')
        # 获取表名
        table_name = self.get_table_name(name)
        if self.cursor:
            self.cursor.execute(self.sql, (table_name, self.data_base))
            columns = self.cursor.fetchall()
        # 字段列表
        columnList = list()
        # 写resultmap
        for (column, typeStr) in columns:
            columnList.append(column)
            column_camel = re.sub(r"(\s|_|-)+", " ", column).title().replace(" ", "")
            column_camel = column_camel[0].lower() + column_camel[1:]
            if column.find('_') < 0:
                continue
            if column == 'id':
                continue
            file.write('''        <result column="''' + column + '''" property="''' + column_camel + '''"/>\n''')
        file.write('    </resultMap>\n')
        file.write('    <sql id="baseColumn">\n')
        columnListStr = str(columnList).replace('\'', '').replace('[', '').replace(']', '')
        file.write('        ' + columnListStr + '\n')
        file.write('    </sql>\n')
        # getbyid
        file.write('    <select id="get" resultMap="baseResultMap">\n')
        file.write('        SELECT\n')
        file.write('        <include refid="baseColumn"/>\n')
        file.write('        FROM ' + table_name + '\n')
        file.write('        WHERE id=#{id}\n')
        file.write('    </select>\n')
        file.write('\n')
        # findlist
        file.write('    <select id="findList" resultMap="baseResultMap">\n')
        file.write('        SELECT\n')
        file.write('        <include refid="baseColumn"/>\n')
        file.write('        FROM ' + table_name + '\n')
        file.write('        WHERE status = 0\n')
        file.write('    </select>\n')
        file.write('\n')
        # insert
        file.write('    <insert id="insert" keyProperty="id" useGeneratedKeys="true">\n')
        file.write('        INSERT INTO ' + table_name + '\n')
        file.write('        (' + columnListStr + ')\n')
        file.write('        VALUES\n        (')
        for i in range(len(columnList) - 2):
            var = self.first_low(self.get_table_name(columnList[i]))
            file.write('#{' + var + '},')
        file.write('SYSDATE(),SYSDATE())')
        file.write('\n')
        file.write('    </insert>\n')
        # update
        file.write('    <update id="update">\n')
        file.write('        UPDATE ' + table_name + '\n')
        file.write('        SET ')
        columnStrList = list()
        for columnStr in columnList:
            columnStr = columnStr + '=#{' + self.first_low(self.get_table_name(columnStr)) + '}'
            columnStrList.append(columnStr)
        file.write(','.join(columnStrList))
        file.write('\n        WHERE status = 0 AND id = #{id}\n')
        file.write('    </update>\n')
        # delete
        file.write('    <delete id="delete">\n')
        file.write('        UPDATE ' + table_name + '\n')
        file.write('        SET status=-1\n')
        file.write('        WHERE status = 0 AND FIND_IN_SET(id, #{idStr})\n')
        file.write('    </delete>\n')
        file.write('</mapper>\n')
        file.flush()
        file.close()

    # 写字段
    def write_model(self, file, tableName):
        if self.cursor:
            self.cursor.execute(self.sql, (self.get_table_name(tableName), self.data_base))
            columns = self.cursor.fetchall()
        for (column, typeStr) in columns:
            if typeStr.find('int') != -1:
                typeStr = 'Integer'
            elif typeStr.find('char') != -1:
                typeStr = 'String'
            elif typeStr.find('date') != -1:
                typeStr = 'Date'
            elif typeStr.find('decimal') != -1:
                typeStr = 'Double'
            elif typeStr.find('blob') != -1:
                typeStr = 'String'
            column = re.sub(r"(\s|_|-)+", " ", column).title().replace(" ", "")
            column = column[0].lower() + column[1:]
            file.write('    private ' + typeStr + ' ' + column + ';\n')

    # 处理字符串：表名变成驼峰标识
    def getClassNameStr(self, x):
        result = self.get_table_name(x)
        index = result.find('_')
        result = result[index + 1:]
        result = re.sub(r"(\s|_|-)+", " ", result).title().replace(" ", "")
        return result

    # 处理表名
    def get_table_name(self, name):
        result = str(name)
        result = result.replace('(', '')
        result = result.replace('\'', '')
        result = result.replace(',', '')
        result = result.replace(')', '')
        return result

    # 第一个小写
    def first_low(self, x):
        x = str(x)
        return x[0].lower() + x[1:]

    # 写一套
    def generate(self, name):
        if str(name).find('20') != -1:
            return
        self.write_DO(name)
        self.plainTextEdit.appendPlainText(self.getClassNameStr(name) + 'DO生成完成')
        self.write_VO(name)
        self.plainTextEdit.appendPlainText(self.getClassNameStr(name) + 'VO生成完成')
        self.write_DTO(name)
        self.plainTextEdit.appendPlainText(self.getClassNameStr(name) + 'DTO生成完成')
        self.write_xml(name)
        self.plainTextEdit.appendPlainText(self.getClassNameStr(name) + 'xml生成完成')
        self.write_controller(name)
        self.plainTextEdit.appendPlainText(self.getClassNameStr(name) + 'controller生成完成')
        self.write_mapper(name)
        self.plainTextEdit.appendPlainText(self.getClassNameStr(name) + 'mapper生成完成')
        self.write_Query(name)
        self.plainTextEdit.appendPlainText(self.getClassNameStr(name) + 'query生成完成')
        self.write_service(name)
        self.plainTextEdit.appendPlainText(self.getClassNameStr(name) + 'service生成完成')

    # 初始化
    def generate_init(self):
        self.get_global_param()
        if not os.path.exists(self.basePath):
            self.generate_dirs()
        else:
            qm.information(self, '提示', '目录' + self.basePath + '已存在')
            return
        self.write_main()
        self.write_page_util()
        self.plainTextEdit.appendPlainText('PageUtil生成完成')
        self.write_base_query()
        self.plainTextEdit.appendPlainText('BaseQuery生成完成')
        self.write_entity_util()
        self.plainTextEdit.appendPlainText('EntityUtil生成完成')
        self.write_rs()
        self.plainTextEdit.appendPlainText('Rs,PageRs生成完成')
        self.write_constant()
        self.write_baseMapper()
        self.plainTextEdit.appendPlainText('BaseMapper生成完成')
        index = 1
        # 进度条
        for name in self.tables:
            self.progressBar.setValue(index * 100 // len(self.tables))
            self.generate(name)
            index += 1
        qm.information(self, '提示', '初始化完成')

    # 触发添加表的一套
    def go_generate(self):
        name, ok = QInputDialog.getText(self, '添加表', '请输入表名', QLineEdit.Normal, 'arc_terminal')
        if len(name) < 1:
            qm.information(self, '提示', '请填入表名')
            return
        self.get_global_param()
        if not os.path.exists(self.basePath):
            self.generate_dirs()
        self.cursor.execute(self.sql, (name, self.data_base))
        if len(self.cursor.fetchall()) < 1:
            qm.information(self, '提示', '该表不存在')
            return
        self.generate(name)
        qm.information(self, '提示', '添加成功')

    # 生成目录结构
    def generate_dirs(self):
        os.makedirs(self.basePath)
        if not os.path.exists(self.basePath + '/controller'):
            os.makedirs(self.basePath + '/controller')
        if not os.path.exists(self.basePath + '/service'):
            os.makedirs(self.basePath + '/service')
        if not os.path.exists(self.basePath + '/model/vo'):
            os.makedirs(self.basePath + '/model/vo')
        if not os.path.exists(self.basePath + '/model/dto'):
            os.makedirs(self.basePath + '/model/dto')
        if not os.path.exists(self.basePath + '/model/query'):
            os.makedirs(self.basePath + '/model/query')
        if not os.path.exists(self.basePath + '/mapper/master'):
            os.makedirs(self.basePath + '/mapper/master')
        if not os.path.exists(self.basePath + '/main/resources/mapper/master'):
            os.makedirs(self.goalpath + '/main/resources/mapper/master')
        if not os.path.exists(self.basePath + '/common/rs'):
            os.makedirs(self.basePath + '/common/rs')
        if not os.path.exists(self.basePath + '/common/util'):
            os.makedirs(self.basePath + '/common/util')

        self.plainTextEdit.appendPlainText('目录生成完成')

    # 接受界面参数并赋值到全局变量
    def get_global_param(self):
        self.host = self.entry_host.text()
        self.port = self.entry_port.text()
        self.user = self.entry_user.text()
        self.password = self.entry_pwd.text()
        # 连接数据库
        try:
            self.conn = pymysql.connect(self.host, self.user, self.password, self.db, int(self.port))
            if not self.conn:
                raise RuntimeError()
            self.cursor = self.conn.cursor()
            self.cursor.execute(self.sql1, self.data_base)
            if not self.cursor:
                raise RuntimeError()
            self.tables = self.cursor.fetchall()
        except Exception:
            qm.information(self, '提示', '数据库连接失败')
            return
        self.author = self.entry_author.text()
        self.goalpath = self.filePathlineEdit.text()
        if len(self.goalpath) < 1:
            qm.information(self, '提示', '请选择目录')
        if len(self.entry_company.text()) > 0:
            self.javapath = self.entry_company.text()
            project_str = self.javapath.replace('.', '/')
            self.basePath = self.goalpath + '/main/java/' + project_str
        if len(self.entry_db.text()) > 0:
            self.data_base = self.entry_db.text()

    def openFile(self):
        get_directory_path = QFileDialog.getExistingDirectory(self,
                                                              "选取指定文件夹",
                                                              "D:/")
        self.filePathlineEdit.setText(str(get_directory_path))
        # 通过包路径获取应用名

    def get_app_name(self, x):
        str_list = str(x).split('.')
        return str_list[-1].title()


if __name__ == "__main__":
    app = QApplication(sys.argv)
    myWin = MyMainForm()
    myWin.show()
    sys.exit(app.exec_())

# # 窗口
# # 初始化按钮
# window = tk.Tk()
# window.title('Generate')
# window.geometry('350x300')
# b = tk.Button(window, text='初始化', command=generate_init)
# b.grid(column=0, row=0)
# # 数据库主机
# label_self.host = tk.Label(window, text='数据库主机', bg='red')
# label_self.host.grid(column=0, row=1)
# value_self.host = tk.StringVar()
# value_self.host.set(self.host)
# entry_self.host = tk.Entry(textvariable=value_self.host)
# entry_self.host.grid(column=0, row=2)
# # 数据库端口
# label_port = tk.Label(window, text='数据库端口', bg='red')
# label_port.grid(column=0, row=3)
# value_port = tk.StringVar()
# value_port.set(port)
# entry_port = tk.Entry(textvariable=value_port)
# entry_port.grid(column=0, row=4)
# # 数据库用户名
# label_self.user = tk.Label(window, text='数据库用户名', bg='red')
# label_self.user.grid(column=0, row=5)
# value_self.user = tk.StringVar()
# value_self.user.set(self.user)
# entry_self.user = tk.Entry(textvariable=value_self.user)
# entry_self.user.grid(column=0, row=6)
# # 数据库密码
# label_pwd = tk.Label(window, text='数据库密码', bg='red')
# label_pwd.grid(column=0, row=7)
# value_pwd = tk.StringVar()
# value_pwd.set(self.password)
# entry_pwd = tk.Entry(show='*', textvariable=value_pwd)
# entry_pwd.grid(column=0, row=8)
# # 数据库
# label_db = tk.Label(window, text='数据库', bg='red')
# label_db.grid(column=0, row=9)
# value_db = tk.StringVar()
# value_db.set(self.data_base)
# entry_db = tk.Entry(textvariable=value_db)
# entry_db.grid(column=0, row=10)
# # 生成按钮
# button_generate = tk.Button(window, text='添加', command=go_generate)
# button_generate.grid(column=1, row=0)
# # 生成文件夹目录
#
# button_dir = tk.Button(window, text='选择目录', command=get_dir)
# button_dir.grid(column=1, row=1)
#
# label_dir = tk.Label(window, text='项目目录', bg='blue')
# label_dir.grid(column=1, row=2)
# # 项目名
# label_company = tk.Label(window, text='包路径', bg='blue')
# label_company.grid(column=1, row=3)
# value_com = tk.StringVar()
# value_com.set('' + self.javapath + '')
# entry_company = tk.Entry(textvariable=value_com)
# entry_company.grid(column=1, row=4)
# # 作者
# label_self.author = tk.Label(window, text='作者', bg='blue')
# label_self.author.grid(column=1, row=5)
# value_self.author = tk.StringVar()
# value_self.author.set(self.author)
# entry_self.author = tk.Entry(textvariable=value_self.author)
# entry_self.author.grid(column=1, row=6)
# # 表名
# label_name = tk.Label(window, text='表名', bg='blue')
# label_name.grid(column=1, row=7)
# entry_table_name = tk.Entry()
# entry_table_name.grid(column=1, row=8)
# window.mainloop()
